<?php
defined('SYS_RUN') or exit();

abstract class Singleton {
    protected $objectStack = array();

    abstract protected function getPath();

    abstract protected function getClassFilePattern();

    abstract protected function getClassPrefix();

    protected function _includeLib($class) {
        $file = $this->_getClassFile($class);

        if (file_exists($file)) {
            include_once $file;
        } else {
            Error::trigger('Not found class file: '.$file);
            return false;
        }
    }

    protected function _getObject($class, $params = array()) {
        $class = $this->_getClassName($class);

        $s_hash = md5($class . serialize($params));

        if (isset($this->objectStack[$s_hash])) {
            return $this->objectStack[$s_hash];
        }

        if (!class_exists($class)) {
            Error::trigger('Class not found: ' . $class);
        }
        if (count($params)) {
            $this->objectStack[$s_hash] = new $class($params);
        } else {
            $this->objectStack[$s_hash] = new $class();
        }

        return $this->objectStack[$s_hash];
    }

    private function _getClassFile($class) {
        $data = $this->_prepareClass($class);
        $classPattern = $this->getClassFilePattern();
        $file = str_replace('{class}', ucfirst($data['name']), $classPattern);
        $file = str_replace('{dir}', ucfirst($data['dir']), $file);
        return DIR_SYS.$data['path'].$file;
    }

    private function _getClassName($class) {
        $data = $this->_prepareClass($class);
        return $this->getClassPrefix().ucfirst($data['name']);
    }

    private function _prepareClass($class) {
        $classPath = $this->getPath();
        $subDir = '';
        if(strrpos($class, '.')) {
            $parts = explode('.', $class);
            if(count($parts) == 2) {
                $subDir = $parts[0].'/';
                $class = ucfirst($parts[1]);
            } else {
                foreach($parts as $part) {
                    if($part == end($parts))
                        $class = ucfirst($part);
                    else
                        $classPath .= $part.'/';
                }
            }
        } else {
            $class = ucfirst($class);
            $subDir = ucfirst($class).'/';
        }
        return array(
            'name'  => $class,
            'path'  => $classPath,
            'dir'   => $subDir
        );
    }
}